The @View annotation can be used in an entity or embeddable class in order to define the layout of its members in the user interface.
The syntax for @View is:
name (optional): This name identifies the view, and can be used in other OpenXava places (for example in application.xml) or from another entity. If the view has no name then the view is assumed as the default one, that is the natural form to display an object of this type.
members (optional): Indicates the members to display and its layout in the user interface. By default it displays all members (excluding hidden ones) in the order in which are declared in the model. Inside members you can use section and group elements for layout purposes; or action element for showing a link associated to a custom action inside your view.
You can define several views for an entity using the @Views annotation.
By default (if you do not use @View) all members are displayed in the order of the model, and one for each line.
For example, a model like this:
You can observe that the member names are separated by commas or by semicolon, this is used to indicate layout. With comma the member is placed just the following (at right), and with semicolon the next member is put below (in the next line). Hence the previous view is displayed in this way:
Groups
With groups you can lump a set of related properties and it has visual effect. For defining a group you only need to put the name of the group and after it its members within square brackets. Just in this way:
@View(members=
"id [ zoneNumber, officeNumber, number ];" +
"name")
In this case the result is:
You can see the three properties within the group are displayed inside a frame, and name is displayed outside this frame. The semicolon before name causes it to appear below, if not it appears at right.
You can put several groups in a view:
In this case the view is shown this way:
Nested groups are allowed. This is a pretty feature that allows you to layout the elements of the user interface in a flexible and simple way. For example, you can define a view as this:
Note that now you use [# instead of [. Now you obtain this result:
Now, thanks to the #, the members are aligned by columns.
This feature is also available for the sections (see below).
Sections
Furthermore the members can be organized in sections. For defining a section you only need to put the name of the section and after it its members within braces. Let's see an example from the Invoice entity:
The visual result is:
The sections are rendered as tabs that the user can click to see the data contained in that section. You can observe how in the view you put members of all types (not only properties); thus, customer is a reference, details and deliveries are collections.
Nested sections are allowed. For example, you can define a view as this:
It's worth to notice that you have groups instead of frames and sections instead of tabs. Because OpenXava tries to maintain a high level of abstraction, that is, a group is a set of members semantically related, and the sections allow to split the data into parts. This is useful, if there is a big amount of data that cannot be displayed simultaneous. The fact that the group is displayed as frames or sections in a tabbed pane is only an implementation issue. For example, OpenXava (maybe in future) can choose to display sections (for example) with trees or so.
Rules for view annotations
You can annotate a member (property, reference or collection) with several annotations that refine its display style and behaviour. Moreover you can define that effect of these annotations only applies to some views.
For example if you have an entity as this one:
In this way name is read only in all views. However, you may want that name will be read only only on views B and C, then you can define the member as following:
Using notForViews you indicate the views where name property is not read only. DEFAULT is used for referencing to the default view, the view with no name.
Some annotations have one or more values, for example for indicating which view of the referenced type will be used for displaying a reference you use the @ReferenceView annotation:
@ReferenceView("Simple")private Seller seller;
In this case when the seller is displayed the view Simple, defined in Seller class, is used.
What if you want to use Simple view of Seller only in B view of Customer? It's easy:
What if you want to use Simple view of Seller only in B view of Customer and the VerySimple view of Seller for A view of Customer? In this case you have to use several @ReferenceView grouping them with @ReferenceViews, just in this way:
All these annotations follow the rules for view annotations and all they are optionals. OpenXava always assumes a correct default values if they are omitted.
@ReadOnly (OX): If you mark a property with this annotation it never will be editable by the final user in this view. An alternative to this is to make the property editable or not editable programmatically using org.openxava.view.View.
@DisplaySize (OX): The size in characters of the editor in the User Interface used to display this property. The editor display only the characters indicated by @DisplaySize but it allows to the user to entry until the total size of the property. If @DisplaySize is not specified, the value of the size of the property is assumed.
@OnChange (OX): Action to execute when the value of this property changes. Only one @OnChange action per view is allowed.
@Action (OX): Actions (showed as links, buttons or images to the user) associated (visually) to this property and that the final user can execute. It's possible to define several @Action for each view.
@Editor (OX): Name of the editor to use for displaying the property in this view. The editor must be declared in OpenXava/xava/default-editors.xml or xava/editors.xml of your project.
In this case the zip code is displayed as:
The LabelFormatType.NORMAL format is the default style (with a normal label at the left) and the LabelFormatType.NO_LABEL simply does not display the label.
Property value change event
If you wish to react to the event of a value change of a property you can use @OnChange as following:
The action has to implement IOnChangePropertyAction although it is more convenient to extend it from OnChangePropertyBaseAction (1). Within the action you can use getNewValue() (2) that provides the new value entered by user, and getView() (3) that allows you to access programmatically the View (change values, hide members, make them editable and so on).
Actions of property
You can also specify actions (@Action) that the user can click directly:
In this case instead of an action class you have to write the action identifier that is the controller name and the action name. This action must be registered in controllers.xml in this way:
<controllername="Delivery">
...
<actionname="generateNumber"hidden="true"class="org.openxava.test.actions.GenerateDeliveryNumberAction"><use-objectname="xava_view"/><!-- Not needed since v4m2 --></action>
...
</controller>
The actions are displayed as a link or an image beside the property. Like this:
By default the action link is present only when the property is editable, but if the property is read only (@ReadOnly) or calculated then it is always present. You can use the attribute alwaysEnabled to true so that the link is always present, even if the property is not editable. As following:
A simple but illustrative implementation. You can use any action defined in controllers.xml and its behavior is the normal for an OpenXava action. In the chapter 7 you will learn more details about actions.
Optionally you can make your action an IPropertyAction (this is only available for actions associated to properties with @Action annotation), thus the container view and the property name are injected in the action by OpenXava. The above action class could be rewritten in this way:
This action implements IPropertyAction (1), this required that the class implements setProperty() (3) and setView() (4), these values are injected in the action object before call to execute() method, where they can be used (2). In this case you does not need to inject xava_view object when defining the action in controllers.xml. The view injected by setView() (4) is the inner view that contains the property, for example, if the property is inside an aggregate the view is the view of that aggregate not the main view of the module. Thus, you can write more reusable actions.
Choosing an editor
An editor display the property to the user and allows him to edit its value. OpenXava uses by default the editor associated to the stereotype or type of the property, but you can specify a concrete editor for display a property using @Editor.
For example, OpenXava uses a combo for editing the properties of type enum, but if you want to display a property of this type in some particular view using a radio button you can define that view in this way:
@Editor(forViews="TypeWithRadioButton", value="ValidValuesRadioButton")privateType type;publicenumType{ NORMAL, STEADY, SPECIAL };
In this case for displaying/editing the editor ValidValuesRadioButton will be used, instead of default one. ValidValueRadioButton is defined in OpenXava/xava/default-editors.xml as following:
This editor is included with OpenXava, but you can create your own editors with your custom JSP code and declare them in the file xava/editors.xml of your project.
This feature is for changing the editor only in one view. If you want to change the editor for a type, steroetype or a property of a model at application level then it's better to configure it using xava/editors.xml file.
Reference customization
You can refine the visual aspect and behavior of a reference in a view using the next annotations:
All these annotations follow the rules for view annotations and all they are optionals. OpenXava always assumes a correct default values if they are omitted.
@ReferenceView (OX): If you omit this annotation, then the default view of the referenced object is used. With this annotation you can indicate that it uses another view.
@ReadOnly (OX): If you use this annotation the reference never will be editable by final user in this view. An alternative is to make the property editable/uneditable programmatically using org.openxava.view.View.
@NoFrame (OX): If the reference is displayed with no frame. By default the references are displayed with frame.
@NoCreate (OX): By default the final user can create new objects of the referenced type from here. If you use this annotation this will not be possible.
@NoModify (OX): By default the final user can modify the current referenced object from here. If you use this annotation this will not be possible.
@NoSearch (OX): By default the user will have a link to make searches with a list, filters, etc. If you use this annotation this will not be possible.
@AsEmbedded (OX): By default in the case of a reference to an embeddable the user can create and edit its data, while in the case of a reference to an entity the user can only to choose an existing entity. If you put @AsEmbedded then the user interface for references to entities behaves as a in the embedded case, allowing to the user to create a new object and editing its data directly. It has no effect in case of a reference to embeddables. Warning! If you remove an entity its referenced entities are not removed, even if they are displayed using @AsEmbedded.
@SearchAction (OX): Allows you to specify your own action for searching when the user click in the search link. Only one by view is allowed.
@DescriptionsList (OX): Display the data as a list of descriptions, typically as a combo. Useful when there are few elements of the referenced object.
@LabelFormat (OX): Format to display the label of the reference. It only applies if this reference is annotated with @DescriptionsList. Works as in property case.
@Action (OX): Actions (showed as links, buttons or images to the user) associated (visually) to this reference and that the final user can execute. Works as in property case. You can define several actions for each reference in the same view.
@OnChange (OX): Action to execute when the value of this reference changes. Only one @OnChange action by view is allowed.
@OnChangeSearch (OX): Allows you to specify your own action for searching when the user type a new key. Only one by view is allowed.
If you do not use any of these annotations OpenXava draws a reference using the default view. For example, if you have a reference like this:
@ManyToOne
private Family family;
The user interface will look like this:
Choose view
The most simple customization is to specify the view of the referenced object that you want to use. This is done by means of @ReferenceView:
The final user can search a new value for the reference simply by keying the new code and leaving the editor the data of reference is obtained; for example, if the user keys "1" on the seller number field, then the name (and the other data) of the seller "1" will be automatically filled. Also the user can click in the lantern, in this case the user will go to a list where he can filter, order, etc, and mark the wished object.
To define your custom search logic you have to use @SearchAction in this way:
When the user clicks in the lantern your action is executed, which must be defined in controllers.xml.
<controllername="MyReference"><actionname="search"hidden="true"class="org.openxava.test.actions.MySearchAction"image="images/search.gif"><use-objectname="xava_view"/><!-- Not needed since v4m2 --><use-objectname="xava_referenceSubview"/><!-- Not needed since v4m2 --><use-objectname="xava_tab"/><!-- Not needed since v4m2 --><use-objectname="xava_currentReferenceLabel"/><!-- Not needed since v4m2 --></action>
...
</controller>
The logic of your MySearchAction is up to you. You can, for example, refining the standard search action to filter the list for searching, as follows:
packageorg.openxava.test.actions;importorg.openxava.actions.*;/**
* @author Javier Paniza
*/publicclass MySearchAction extends ReferenceSearchAction {publicvoid execute()throwsException{super.execute();// The standard search behaviour
getTab().setBaseCondition("${number} < 3");// Adding a filter to the list}}
If you do not use @NoCreate annotation the user will have a link to create a new object. By default when a user clicks on this link, a default view of the referenced object is displayed and the final user can type values and click a button to create it. If you want to define your custom actions (among them your create custom action) in the form used when creating a new object, you must have a controller named as component but with the suffix Creation. If OpenXava see this controller it uses it instead of the default one to allow creating a new object from a reference. For example, you can write in your controllers.xml:
<!--Because its name is WarehouseCreation (model name + Creation) it is usedby default for create from reference, instead of NewCreation.Action 'new' is executed automatically.--><controllername="WarehouseCreation"><extendscontroller="NewCreation"/><actionname="new"hidden="true"class="org.openxava.test.actions.CreateNewWarehouseFromReferenceAction"><use-objectname="xava_view"/><!-- Not needed since v4m2 --></action></controller>
In this case when the user clicks on the 'create' link, the user is directed to the default view of Warehouse and the actions in WarehouseCreation will be allowed.
If you have an action called 'new', it will be executed automatically before all. It can be used to initialize the view used to create a new object.
Custom modification action
If you do not use @NoModify the user will have a link to modify the current referenced object. By default when a user clicks on this link, a default view of the referenced object is displayed and the final user can modify values and click a button to update it. If you want to define your custom actions (among them your update custom action) in the form used when modifying the current object, you must have a controller named as component but with the suffix Modification. If OpenXava see this controller it uses it instead of the default one to allow modifying the current object from a reference. For example, you can write in your controllers.xml:
<!--Because its name is WarehouseModification (model name + Modification) it is usedby default for modifying from reference, instead of Modification.The action 'search' is executed automatically.--><controllername="WarehouseModification"><extendscontroller="Modification"/><actionname="search"hidden="true"class="org.openxava.test.actions.ModifyWarehouseFromReferenceAction"><use-objectname="xava_view"/><!-- Not needed since v4m2 --></action></controller>
In this case when the user clicks on the 'modify' link, the user is directed to the default view of Warehouse and the actions in WarehouseModification will be allowed.
If you have an action called 'search', it will be executed automatically before all. It is used to initialize the view with the object to modify.
Descriptions list (combos)
With @DescriptionsList you can instruct OpenXava to visualize references as a descriptions list (actually a combo). This can be useful, if there are only a few elements and these elements have a significant name or description.
The syntax is:
descriptionProperties (optional): The property or properties to show in the list, if not specified, the property named description, descripcion, name or nombre is assumed. If the referenced object does not have a property called this way then it is required to specify a property name here. It allows to set more than one property separated by commas. To the final user the values are concatenated.
depends (optional): It's used in together with condition. It can be achieve that the list content depends on another value displayed in the main view (if you simply type the name of the member) or in the same view (if you type this. before the name of the member).
condition (optional): Allows to specify a condition (with SQL style) to filter the values that are shown in the description list.
orderByKey (optional): By default the data is ordered by description, but if you set this property to true it will be ordered by key.
order (optional): Allows to specify an order (with SQL style) for the values that are shown in the description list.
That displays a reference to warehouse in this way:
In this case it shows all warehouses, although in reality it uses the baseCondition and the filter specified in the default @Tab of Warehouse. You will see more about tabs in chapter 5.
If you want, for example, to display a combo with the product families and when the user chooses a family, then another combo will be filled with the subfamilies of the chosen family. An implementation can look like this:
Two combos are displayed one with all families loaded and the other one empty. When the user chooses a family, then the second combo is filled with all its subfamilies.
In the case of Family the property description of Family is shown, since the default property to show is 'description' or 'name'. The data is ordered by key and not by description (1). In the case of Subfamily (2) the link to create a new subfamily is not shown and the property to display is 'description' (in this case this maybe omitted).
With depends (4) you make that this combo depends on the reference family, when change family in the user interface, this descriptions list is filled applying the condition condition (5) and sending as argument (to set value to ?) the new family value. And the entries are ordered descending by description (6).
In condition and order you put the property name inside a ${} and the arguments as ?. The comparator operators are the SQL operators.
You can specify several properties to be shown as description:
In this case the concatenation of the description of level and the name is shown in the combo. Also you can see how it is possible to use qualified properties (level.description).
If you use @ReadOnly in a reference annotated as @DescriptionsList, then the description (in this case level.description + name) is displayed as a simple text property instead of using a combo.
Reference value change event
If you wish to react to the event of a value change of a reference you can write:
In this case your action listens to the change of carrier number.
The code to execute is:
packageorg.openxava.test.actions;importorg.openxava.actions.*;/**
* @author Javier Paniza
*/publicclass OnChangeCarrierInDeliveryAction
extends OnChangePropertyBaseAction {// 1publicvoid execute()throwsException{if(getNewValue() == null)return;
getView().setValue("remarks", "The carrier is " + getNewValue());
addMessage("carrier_changed");}}
The action implements IOnChangePropertyAction, by means of OnChangePropertyBaseAction (1), although it's a reference. We receive the change of the key property of the reference; in this case carrier.number. The rest is as in the property case.
Reference search on change event
The user can search the value of a reference simply typing its key. For example, if there is a reference to Subfamily, the user can type the subfamily number and automatically the subfamily data is loaded in the view. This is done using a default on change action that does the search. You can specify your own action for search when key change using @OnChangeSearch annotation, just in this way:
The action implements IOnChangePropertyAction, by means of OnChangeSearchAction (1), although it's a reference. It receives the change of the key property of the reference; in this case subfamily.number.
This case is an example of refining the behaviour of on change search, because it extends from OnChangeSearchAction, that is the default action for searching, and calls to super.execute(). Also it's possible to do a regular on change action (extending from OnChangePropertyBaseAction for example) overriding completely the search logic.
Collection customization
You can refine the visual aspect and behavior of a collection in a view using the next annotations:
All these annotations follow the rules for view annotations and all they are optionals. OpenXava always assumes a correct default values if they are omitted.
@CollectionView (OX): The view of the referenced object (each collection element) which is used to display the detail. By default the default view is used.
@ReadOnly (OX): If you set it then the final user only can view collection elements, he cannot add, delete or modify elements.
@EditOnly (OX): If you set it then the final user can modify existing elements, but not add or remove collection elements.
@NoCreate (OX): If you set it then the final user doesn't get the link to create new objects of the referenced object type. It does not apply to embedded collections.
@NoModify (OX): If you set it then the final user doesn't get the link to modify the objects of the referenced object type. It does not apply to embedded collections.
@AsEmbedded (OX): By default the embedded collections (with cascade type REMOVE or ALL) allow the users to create and to edit elements, while the regular collections allow only to choose existing entities to add to (or remove from) the collection. If you put @AsEmbedded then the collection behaves as a embedded collection even though it hasn't cascade type REMOVE or ALL, allowing to the user to add objects and editing them directly. It has no effect in case of embedded collections.
@ListProperties (OX): Properties to show in the list for visualization of the collection. You can qualify the properties. By default it shows all persistent properties of the referenced object (excluding references and calculated properties).
@RowStyle (OX): To give a special style to some rows. Behaves equals that in the Tab case. It does not works for calculated collections. It's possible to define several @RowStyle for each view.
@EditAction (OX): Allows you to define your custom action to begin the editing of a collection element. This is the action showed in each row of the collection, if the collection is editable. Only one @EditAction per view is allowed.
@ViewAction (OX): Allows you to define your custom action to view a collection element. This is the action showed in each row, if the collection is read only. Only one @ViewAction per view is allowed.
@NewAction (OX): Allows you to define your custom action to start adding a new element to the collection. This is the action executed on click in 'Add' link. Only one @ViewAction per view is allowed.
@SaveAction (OX): Allows you to define your custom action to save the collection element. This is the action executed on click in 'Save detail' link. Only one @SaveAction per view is allowed.
@HideDetailAction (OX): Allows you to define your custom action to hide the detail view. This is the action executed on click in 'Close' link. Only one @HideDetailAction per view is allowed.
@RemoveAction (OX): Allows you to define your custom action to remove the element from the collection. This is the action executed on click in 'Remove detail' link. Only one @RemoveAction per view is allowed.
@RemoveSelectedAction (OX): Allows you to define your custom action to remove the selected elements from the collection. This is the action executed when a user select some rows and then click in 'Remove selected' link. Only one @RemoveSelectedAction per view is allowed.
@ListAction (OX): To add actions in list mode; usually actions which scope is the entire collection. It's possible to define several @ListAction for each view.
@DetailAction (OX): To add actions in detail mode, usually actions which scope is the detail that is being edited. It's possible to define several @DetailAction for each view.
If you do not use any of these annotations then the collection is displayed using the persistent properties in list mode and the default view to represent the detail; although in typical scenarios the properties of the list and the view for detail are specified:
And the collection is displayed: You see how you can put qualified properties into the properties list (as seller.level.description).
When the user clicks on ('Edit'), then the view Simple of Customer will be rendered; for this you must have defined a view called Simple in the Customer entity (the model of the collection elements).
This view is also used if the user click on ('Add') in an embedded collection, otherwise OpenXava does not show this view, instead it shown a list of entities to add.
If the view Simple of Customer is like this:
You have to define Invoices.editDetail in controllers.xml:
<controllername="Invoice">
...
<actionname="editDetail"hidden="true"image="images/edit.gif"class="org.openxava.test.actions.EditInvoiceDetailAction"><use-objectname="xava_view"/><!-- Not needed since v4m2 --></action>
...
</controller>
In this case you only refine hence your action extends (1) EditElementInCollectionAction. In this case you only specify a default value for the remarks property. Note that to access the view that displays the detail you can use the method getCollectionElementView() (2).
Also it's possible to remove the edit action from the User Interface, in this way:
You only need to put an empty string as value for the action. Although in most case it's enough to define the collection as @ReadOnly.
The technique to refine the view action (the action for each row, if the collection is read only) is the same but using @ViewAction instead of @EditAction.
Custom list actions
Adding our custom list actions (actions that apply to entire collections) is easy using @ListAction:
The action extends CollectionBaseAction (1), this way you can use methods as getSelectedObjects() (2) that returns a collection with the objects selected by the user. There are others useful methods, as getObjects() (all elements collection), getMapValues() (the collection values in map format) and getMapsSelectedValues() (the selected elements in map format).
As in the case of detail actions (see next section) you can use getCollectionElementView().
Also it's possible to use actions for list mode as list actions for a collection.
Default list actions
If you want to add some custom list actions to all the collection of your application you can do it creating a controller called DefaultListActionsForCollections in your own xava/controllers.xml file as following:
In this way all the collections will have the actions of Print controller (for export to Excel and generate PDF report) and your own ExportAsXMLAction. This has the same effect of @ListAction (look at custom list actions section) but it applies to all collections at once.
This feature does not apply to calculated collections.
Custom detail actions
Also you can add your custom actions to the detail view used for editing each element. This is accomplish by means of @DetailAction annotation. These actions are applicable only to one element of collection. For example:
In this way the user has another link to click in the detail of the collection element:
You need to define the action in controllers.xml:
<controllername="Invoice">
...
<actionname="viewProduct"hidden="true"class="org.openxava.test.actions.ViewProductFromInvoiceDetailAction"><use-objectname="xava_view"/><!-- Not needed since v4m2 --><use-objectname="xavatest_invoiceValues"/><!-- Not needed since v4m2 --></action>
...
</controller>
You can see that it extends CollectionElementViewBaseAction (1) thus it has available the view that displays the current element using getCollectionElementView() (2). Also you can get access to the main view using getView() (3). In chapter 7 you will see more details about writing actions.
Also, using the view returned by getCollectionElementView() you can add and remove programmatically detail and list actions with addDetailAction(), removeDetailAction(), addListAction() and removeListAction(), see API doc for org.openxava.view.View.
You must have an action DeliveryDetails.save in your controllers.xml:
<controllername="DeliveryDetail">
...
<actionname="save"class="org.openxava.test.actions.SaveDeliveryDetailAction"><use-objectname="xava_view"/><!-- Not needed since v4m2 --></action>
...
</controller>
And define your action class for saving:
packageorg.openxava.test.actions;importorg.openxava.actions.*;/**
* @author Javier Paniza
*/publicclass SaveDeliveryDetailAction extends SaveElementInCollectionAction {// 1publicvoid execute()throwsException{super.execute();// Here your own code // 2}}
The more common case is extending the default behavior, for that you have to extend the original class for saving a collection detail (1), that is SaveElementInCollection action, then call to super from execute() method (2), and after it, writing your own code.
Also it's possible to remove any of these actions from User Interface, for example, you can define a collection in this way:
In this case the action for removing the selected elements in the collection will be missing in the User Interface. As you see, only it's needed to declare an empty string as the name of the action.
Transient properties for UI controls
With @Transient (JPA) you define a property that is not stored in database but you want to show to the user. You can use it to provide UI controls to allow the user to manage his user interface.
An example:
You can see that the syntax is exactly the same as in the case of a regular property of an entity; you can even use enum and @DefaultValueCalculator. After defining the property you can use it in the view as usual, for example with @OnChange or putting it as member of a view.
View actions
In addition of associating actions to a property, reference or collection, you also can define arbitrary actions inside your view, in any place. In order to do this we use the qualified name of action using brackets () as suffix, in this way:
The visual effect will be:
You can see the link 'Change name label' that will execute the action Customer.changeNameLabel on click on it.
If the container view of the action is not editable, the action is not present. If you want that the action is always enabled, even if the view is not editable, you have to use put the word ALWAYS between the brackets, as following:
The standard way to expose actions to the user is using the controllers (actions in a bar), the controllers are reusable between views, but sometimes you will need an action specific to a view, and you want display it inside the view (not in the button bar), for these cases the view actions may be useful.
See more about actions in chapter 7.
Transient class: Only for creating views
In OpenXava it is not possible to have a view without model. Thus if you want to draw an arbitrary user interface, you need to create a class, not to declare it as entity and define your view in it.
An transient class is not associated to any table of the database, typically it's used only for display User Interfaces not related to any data in database.
An example can be:
packageorg.openxava.test.model;importjavax.persistence.*;importorg.openxava.annotations.*;/**
* Example of an transient OpenXava model class (not persistent). <p>
*
* This can be used, for example, to display a dialog,
* or any other graphical interface.<p>
*
* Note that is not marked as @Entity <br>
*
* @author Javier Paniza
*/
@Views({
@View(name="Family1", members="subfamily"),
@View(name="Family2", members="subfamily"),
@View(name="WithSubfamilyForm", members="subfamily"),
@View(name="Range", members="subfamily; subfamilyTo")})publicclass FilterBySubfamily {
@ManyToOne(fetch=FetchType.LAZY) @Required
@NoCreate(forViews="Family1, Family2")
@NoModify(forViews="Family2, WithSubfamilyForm")
@NoSearch(forViews="WithSubfamilyForm")
@DescriptionsLists({
@DescriptionsList(forViews="Family1",
condition="${family.number} = 1", order="${number} desc"),
@DescriptionsList(forViews="Family2",
condition="${family.number} = 2")})private Subfamily subfamily;
@ManyToOne(fetch=FetchType.LAZY)private Subfamily subfamilyTo;public Subfamily getSubfamily(){return subfamily;}publicvoid setSubfamily(Subfamily subfamily){this.subfamily = subfamily;}public Subfamily getSubfamilyTo(){return subfamilyTo;}publicvoid setSubfamilyTo(Subfamily subfamilyTo){this.subfamilyTo = subfamilyTo;}}
For defining a model class as transient you only need to define a regular Java class without @Entity annotation. You mustn't put the mapping annotations nor declare properties as key.
This way you can design a dialog that can be useful, for example, to print a report of families or products filtered by subfamily.
Transient classes are used with only detail modules.
The package for transient model classes must be the same of the persistent classes.
With this simple trick you can use OpenXava as a simple and flexible generator for user interfaces although the displayed data won't be stored.
第4章: 视图
OpenXava 根据模型,可以生成一个缺省的用户界面. 在许多情况下,这就可以了。但有些时候,你需要对用户界面的格式和视图进行精确定义。在本章中,你将学到怎么做。Layout
The @View annotation can be used in an entity or embeddable class in order to define the layout of its members in the user interface.The syntax for @View is:
- name (optional): This name identifies the view, and can be used in other OpenXava places (for example in application.xml) or from another entity. If the view has no name then the view is assumed as the default one, that is the natural form to display an object of this type.
- members (optional): Indicates the members to display and its layout in the user interface. By default it displays all members (excluding hidden ones) in the order in which are declared in the model. Inside members you can use section and group elements for layout purposes; or action element for showing a link associated to a custom action inside your view.
You can define several views for an entity using the @Views annotation.By default (if you do not use @View) all members are displayed in the order of the model, and one for each line.
For example, a model like this:
Generates a view that looks like this:
You can choose the members to display and its order, with the members attribute:
In this case name is not shown.
Also you can use members for tunning the layout:
You can observe that the member names are separated by commas or by semicolon, this is used to indicate layout. With comma the member is placed just the following (at right), and with semicolon the next member is put below (in the next line). Hence the previous view is displayed in this way:
Groups
With groups you can lump a set of related properties and it has visual effect. For defining a group you only need to put the name of the group and after it its members within square brackets. Just in this way:In this case the result is:
You can see the three properties within the group are displayed inside a frame, and name is displayed outside this frame. The semicolon before name causes it to appear below, if not it appears at right.
You can put several groups in a view:
In this case the groups are shown one next to the other:
If you want one below the other then you must use a semicolon after the group, like this:
In this case the view is shown this way:
Nested groups are allowed. This is a pretty feature that allows you to layout the elements of the user interface in a flexible and simple way. For example, you can define a view as this:
And the result will be:
Sometimes it's useful to layout members aligned by columns, like in a table. For example, the next view:
...will be displayed as following:
This is ugly. It would be better to have all data aligned by columns. You can define the group in this way:
Note that now you use [# instead of [. Now you obtain this result:
Now, thanks to the #, the members are aligned by columns.
This feature is also available for the sections (see below).
Sections
Furthermore the members can be organized in sections. For defining a section you only need to put the name of the section and after it its members within braces. Let's see an example from the Invoice entity:The visual result is:
The sections are rendered as tabs that the user can click to see the data contained in that section. You can observe how in the view you put members of all types (not only properties); thus, customer is a reference, details and deliveries are collections.
Nested sections are allowed. For example, you can define a view as this:
In this case you will obtain a user interface like this:
As in the groups case, the sections allow using # for aligning by columns, like this:
With the same effect as in the group case.
Layout philosophy
It's worth to notice that you have groups instead of frames and sections instead of tabs. Because OpenXava tries to maintain a high level of abstraction, that is, a group is a set of members semantically related, and the sections allow to split the data into parts. This is useful, if there is a big amount of data that cannot be displayed simultaneous. The fact that the group is displayed as frames or sections in a tabbed pane is only an implementation issue. For example, OpenXava (maybe in future) can choose to display sections (for example) with trees or so.Rules for view annotations
You can annotate a member (property, reference or collection) with several annotations that refine its display style and behaviour. Moreover you can define that effect of these annotations only applies to some views.For example if you have an entity as this one:
And you want the name property will be read only. You can annotate it in this way:
In this way name is read only in all views. However, you may want that name will be read only only on views B and C, then you can define the member as following:
Another way for defining this same case is:
Using notForViews you indicate the views where name property is not read only. DEFAULT is used for referencing to the default view, the view with no name.
Some annotations have one or more values, for example for indicating which view of the referenced type will be used for displaying a reference you use the @ReferenceView annotation:
In this case when the seller is displayed the view Simple, defined in Seller class, is used.
What if you want to use Simple view of Seller only in B view of Customer? It's easy:
What if you want to use Simple view of Seller only in B view of Customer and the VerySimple view of Seller for A view of Customer? In this case you have to use several @ReferenceView grouping them with @ReferenceViews, just in this way:
These rules apply to all the annotations in this chapter, except @View and @Views.
Property customization
You can refine the visual aspect and behavior of a property in a view using the next annotations:All these annotations follow the rules for view annotations and all they are optionals. OpenXava always assumes a correct default values if they are omitted.
Label format
A simple example of using @LabelFormat:In this case the zip code is displayed as:
The LabelFormatType.NORMAL format is the default style (with a normal label at the left) and the LabelFormatType.NO_LABEL simply does not display the label.
Property value change event
If you wish to react to the event of a value change of a property you can use @OnChange as following:The code to execute is:
The action has to implement IOnChangePropertyAction although it is more convenient to extend it from OnChangePropertyBaseAction (1). Within the action you can use getNewValue() (2) that provides the new value entered by user, and getView() (3) that allows you to access programmatically the View (change values, hide members, make them editable and so on).
Actions of property
You can also specify actions (@Action) that the user can click directly:In this case instead of an action class you have to write the action identifier that is the controller name and the action name. This action must be registered in controllers.xml in this way:
The actions are displayed as a link or an image beside the property. Like this:
By default the action link is present only when the property is editable, but if the property is read only (@ReadOnly) or calculated then it is always present. You can use the attribute alwaysEnabled to true so that the link is always present, even if the property is not editable. As following:
The attribute alwaysEnabled is optional and its default value is false.
The code of previous action is:
A simple but illustrative implementation. You can use any action defined in controllers.xml and its behavior is the normal for an OpenXava action. In the chapter 7 you will learn more details about actions.
Optionally you can make your action an IPropertyAction (this is only available for actions associated to properties with @Action annotation), thus the container view and the property name are injected in the action by OpenXava. The above action class could be rewritten in this way:
This action implements IPropertyAction (1), this required that the class implements setProperty() (3) and setView() (4), these values are injected in the action object before call to execute() method, where they can be used (2). In this case you does not need to inject xava_view object when defining the action in controllers.xml. The view injected by setView() (4) is the inner view that contains the property, for example, if the property is inside an aggregate the view is the view of that aggregate not the main view of the module. Thus, you can write more reusable actions.
Choosing an editor
An editor display the property to the user and allows him to edit its value. OpenXava uses by default the editor associated to the stereotype or type of the property, but you can specify a concrete editor for display a property using @Editor.For example, OpenXava uses a combo for editing the properties of type enum, but if you want to display a property of this type in some particular view using a radio button you can define that view in this way:
In this case for displaying/editing the editor ValidValuesRadioButton will be used, instead of default one. ValidValueRadioButton is defined in OpenXava/xava/default-editors.xml as following:
<editor name="ValidValuesRadioButton" url="radioButtonEditor.jsp"/>This editor is included with OpenXava, but you can create your own editors with your custom JSP code and declare them in the file xava/editors.xml of your project.This feature is for changing the editor only in one view. If you want to change the editor for a type, steroetype or a property of a model at application level then it's better to configure it using xava/editors.xml file.
Reference customization
You can refine the visual aspect and behavior of a reference in a view using the next annotations:All these annotations follow the rules for view annotations and all they are optionals. OpenXava always assumes a correct default values if they are omitted.
- @ReferenceView (OX): If you omit this annotation, then the default view of the referenced object is used. With this annotation you can indicate that it uses another view.
- @ReadOnly (OX): If you use this annotation the reference never will be editable by final user in this view. An alternative is to make the property editable/uneditable programmatically using org.openxava.view.View.
- @NoFrame (OX): If the reference is displayed with no frame. By default the references are displayed with frame.
- @NoCreate (OX): By default the final user can create new objects of the referenced type from here. If you use this annotation this will not be possible.
- @NoModify (OX): By default the final user can modify the current referenced object from here. If you use this annotation this will not be possible.
- @NoSearch (OX): By default the user will have a link to make searches with a list, filters, etc. If you use this annotation this will not be possible.
- @AsEmbedded (OX): By default in the case of a reference to an embeddable the user can create and edit its data, while in the case of a reference to an entity the user can only to choose an existing entity. If you put @AsEmbedded then the user interface for references to entities behaves as a in the embedded case, allowing to the user to create a new object and editing its data directly. It has no effect in case of a reference to embeddables. Warning! If you remove an entity its referenced entities are not removed, even if they are displayed using @AsEmbedded.
- @SearchAction (OX): Allows you to specify your own action for searching when the user click in the search link. Only one by view is allowed.
- @DescriptionsList (OX): Display the data as a list of descriptions, typically as a combo. Useful when there are few elements of the referenced object.
- @LabelFormat (OX): Format to display the label of the reference. It only applies if this reference is annotated with @DescriptionsList. Works as in property case.
- @Action (OX): Actions (showed as links, buttons or images to the user) associated (visually) to this reference and that the final user can execute. Works as in property case. You can define several actions for each reference in the same view.
- @OnChange (OX): Action to execute when the value of this reference changes. Only one @OnChange action by view is allowed.
- @OnChangeSearch (OX): Allows you to specify your own action for searching when the user type a new key. Only one by view is allowed.
If you do not use any of these annotations OpenXava draws a reference using the default view. For example, if you have a reference like this:The user interface will look like this:
Choose view
The most simple customization is to specify the view of the referenced object that you want to use. This is done by means of @ReferenceView:In the Invoice entity you must have a view named Simple:
Thus, instead of using the default view of Invoice (that shows all invoice data) OpenXava will use the next one:
Customizing frame
If you combine @NoFrame with groups you can group visually a property that is not a part of a reference with that reference, for example:And the result:
Custom search action
The final user can search a new value for the reference simply by keying the new code and leaving the editor the data of reference is obtained; for example, if the user keys "1" on the seller number field, then the name (and the other data) of the seller "1" will be automatically filled. Also the user can click in the lantern, in this case the user will go to a list where he can filter, order, etc, and mark the wished object.To define your custom search logic you have to use @SearchAction in this way:
When the user clicks in the lantern your action is executed, which must be defined in controllers.xml.
The logic of your MySearchAction is up to you. You can, for example, refining the standard search action to filter the list for searching, as follows:
You will learn more about actions in chapter 7.
Custom creation action
If you do not use @NoCreate annotation the user will have a link to create a new object. By default when a user clicks on this link, a default view of the referenced object is displayed and the final user can type values and click a button to create it. If you want to define your custom actions (among them your create custom action) in the form used when creating a new object, you must have a controller named as component but with the suffix Creation. If OpenXava see this controller it uses it instead of the default one to allow creating a new object from a reference. For example, you can write in your controllers.xml:In this case when the user clicks on the 'create' link, the user is directed to the default view of Warehouse and the actions in WarehouseCreation will be allowed.
If you have an action called 'new', it will be executed automatically before all. It can be used to initialize the view used to create a new object.
Custom modification action
If you do not use @NoModify the user will have a link to modify the current referenced object. By default when a user clicks on this link, a default view of the referenced object is displayed and the final user can modify values and click a button to update it. If you want to define your custom actions (among them your update custom action) in the form used when modifying the current object, you must have a controller named as component but with the suffix Modification. If OpenXava see this controller it uses it instead of the default one to allow modifying the current object from a reference. For example, you can write in your controllers.xml:In this case when the user clicks on the 'modify' link, the user is directed to the default view of Warehouse and the actions in WarehouseModification will be allowed.
If you have an action called 'search', it will be executed automatically before all. It is used to initialize the view with the object to modify.
Descriptions list (combos)
With @DescriptionsList you can instruct OpenXava to visualize references as a descriptions list (actually a combo). This can be useful, if there are only a few elements and these elements have a significant name or description.The syntax is:
- descriptionProperties (optional): The property or properties to show in the list, if not specified, the property named description, descripcion, name or nombre is assumed. If the referenced object does not have a property called this way then it is required to specify a property name here. It allows to set more than one property separated by commas. To the final user the values are concatenated.
- depends (optional): It's used in together with condition. It can be achieve that the list content depends on another value displayed in the main view (if you simply type the name of the member) or in the same view (if you type this. before the name of the member).
- condition (optional): Allows to specify a condition (with SQL style) to filter the values that are shown in the description list.
- orderByKey (optional): By default the data is ordered by description, but if you set this property to true it will be ordered by key.
- order (optional): Allows to specify an order (with SQL style) for the values that are shown in the description list.
The simplest usage is:That displays a reference to warehouse in this way:
In this case it shows all warehouses, although in reality it uses the baseCondition and the filter specified in the default @Tab of Warehouse. You will see more about tabs in chapter 5.
If you want, for example, to display a combo with the product families and when the user chooses a family, then another combo will be filled with the subfamilies of the chosen family. An implementation can look like this:
Two combos are displayed one with all families loaded and the other one empty. When the user chooses a family, then the second combo is filled with all its subfamilies.
In the case of Family the property description of Family is shown, since the default property to show is 'description' or 'name'. The data is ordered by key and not by description (1). In the case of Subfamily (2) the link to create a new subfamily is not shown and the property to display is 'description' (in this case this maybe omitted).
With depends (4) you make that this combo depends on the reference family, when change family in the user interface, this descriptions list is filled applying the condition condition (5) and sending as argument (to set value to ?) the new family value. And the entries are ordered descending by description (6).
In condition and order you put the property name inside a ${} and the arguments as ?. The comparator operators are the SQL operators.
You can specify several properties to be shown as description:
In this case the concatenation of the description of level and the name is shown in the combo. Also you can see how it is possible to use qualified properties (level.description).
If you use @ReadOnly in a reference annotated as @DescriptionsList, then the description (in this case level.description + name) is displayed as a simple text property instead of using a combo.
Reference value change event
If you wish to react to the event of a value change of a reference you can write:In this case your action listens to the change of carrier number.
The code to execute is:
The action implements IOnChangePropertyAction, by means of OnChangePropertyBaseAction (1), although it's a reference. We receive the change of the key property of the reference; in this case carrier.number. The rest is as in the property case.
Reference search on change event
The user can search the value of a reference simply typing its key. For example, if there is a reference to Subfamily, the user can type the subfamily number and automatically the subfamily data is loaded in the view. This is done using a default on change action that does the search. You can specify your own action for search when key change using @OnChangeSearch annotation, just in this way:This action is executed for doing the search, instead of the standard action, when the user changes the subfamily number.
The code to execute is:
The action implements IOnChangePropertyAction, by means of OnChangeSearchAction (1), although it's a reference. It receives the change of the key property of the reference; in this case subfamily.number.
This case is an example of refining the behaviour of on change search, because it extends from OnChangeSearchAction, that is the default action for searching, and calls to super.execute(). Also it's possible to do a regular on change action (extending from OnChangePropertyBaseAction for example) overriding completely the search logic.
Collection customization
You can refine the visual aspect and behavior of a collection in a view using the next annotations:All these annotations follow the rules for view annotations and all they are optionals. OpenXava always assumes a correct default values if they are omitted.
- @CollectionView (OX): The view of the referenced object (each collection element) which is used to display the detail. By default the default view is used.
- @ReadOnly (OX): If you set it then the final user only can view collection elements, he cannot add, delete or modify elements.
- @EditOnly (OX): If you set it then the final user can modify existing elements, but not add or remove collection elements.
- @NoCreate (OX): If you set it then the final user doesn't get the link to create new objects of the referenced object type. It does not apply to embedded collections.
- @NoModify (OX): If you set it then the final user doesn't get the link to modify the objects of the referenced object type. It does not apply to embedded collections.
- @AsEmbedded (OX): By default the embedded collections (with cascade type REMOVE or ALL) allow the users to create and to edit elements, while the regular collections allow only to choose existing entities to add to (or remove from) the collection. If you put @AsEmbedded then the collection behaves as a embedded collection even though it hasn't cascade type REMOVE or ALL, allowing to the user to add objects and editing them directly. It has no effect in case of embedded collections.
- @ListProperties (OX): Properties to show in the list for visualization of the collection. You can qualify the properties. By default it shows all persistent properties of the referenced object (excluding references and calculated properties).
- @RowStyle (OX): To give a special style to some rows. Behaves equals that in the Tab case. It does not works for calculated collections. It's possible to define several @RowStyle for each view.
- @EditAction (OX): Allows you to define your custom action to begin the editing of a collection element. This is the action showed in each row of the collection, if the collection is editable. Only one @EditAction per view is allowed.
- @ViewAction (OX): Allows you to define your custom action to view a collection element. This is the action showed in each row, if the collection is read only. Only one @ViewAction per view is allowed.
- @NewAction (OX): Allows you to define your custom action to start adding a new element to the collection. This is the action executed on click in 'Add' link. Only one @ViewAction per view is allowed.
- @SaveAction (OX): Allows you to define your custom action to save the collection element. This is the action executed on click in 'Save detail' link. Only one @SaveAction per view is allowed.
- @HideDetailAction (OX): Allows you to define your custom action to hide the detail view. This is the action executed on click in 'Close' link. Only one @HideDetailAction per view is allowed.
- @RemoveAction (OX): Allows you to define your custom action to remove the element from the collection. This is the action executed on click in 'Remove detail' link. Only one @RemoveAction per view is allowed.
- @RemoveSelectedAction (OX): Allows you to define your custom action to remove the selected elements from the collection. This is the action executed when a user select some rows and then click in 'Remove selected' link. Only one @RemoveSelectedAction per view is allowed.
- @ListAction (OX): To add actions in list mode; usually actions which scope is the entire collection. It's possible to define several @ListAction for each view.
- @DetailAction (OX): To add actions in detail mode, usually actions which scope is the detail that is being edited. It's possible to define several @DetailAction for each view.
If you do not use any of these annotations then the collection is displayed using the persistent properties in list mode and the default view to represent the detail; although in typical scenarios the properties of the list and the view for detail are specified:And the collection is displayed:
When the user clicks on
This view is also used if the user click on
If the view Simple of Customer is like this:
On clicking in a detail the following will be shown:
Custom edit/view action
You can refine easily the behavior when theYou have to define Invoices.editDetail in controllers.xml:
And finally write your action:
In this case you only refine hence your action extends (1) EditElementInCollectionAction. In this case you only specify a default value for the remarks property. Note that to access the view that displays the detail you can use the method getCollectionElementView() (2).
Also it's possible to remove the edit action from the User Interface, in this way:
You only need to put an empty string as value for the action. Although in most case it's enough to define the collection as @ReadOnly.
The technique to refine the view action (the action for each row, if the collection is read only) is the same but using @ViewAction instead of @EditAction.
Custom list actions
Adding our custom list actions (actions that apply to entire collections) is easy using @ListAction:Now a new link is shown to the user:
Also you need to define the action in controllers.xml:
And the action code:
The action extends CollectionBaseAction (1), this way you can use methods as getSelectedObjects() (2) that returns a collection with the objects selected by the user. There are others useful methods, as getObjects() (all elements collection), getMapValues() (the collection values in map format) and getMapsSelectedValues() (the selected elements in map format).
As in the case of detail actions (see next section) you can use getCollectionElementView().
Also it's possible to use actions for list mode as list actions for a collection.
Default list actions
If you want to add some custom list actions to all the collection of your application you can do it creating a controller called DefaultListActionsForCollections in your own xava/controllers.xml file as following:In this way all the collections will have the actions of Print controller (for export to Excel and generate PDF report) and your own ExportAsXMLAction. This has the same effect of @ListAction (look at custom list actions section) but it applies to all collections at once.
This feature does not apply to calculated collections.
Custom detail actions
Also you can add your custom actions to the detail view used for editing each element. This is accomplish by means of @DetailAction annotation. These actions are applicable only to one element of collection. For example:In this way the user has another link to click in the detail of the collection element:
You need to define the action in controllers.xml:
And the code of your action:
You can see that it extends CollectionElementViewBaseAction (1) thus it has available the view that displays the current element using getCollectionElementView() (2). Also you can get access to the main view using getView() (3). In chapter 7 you will see more details about writing actions.
Also, using the view returned by getCollectionElementView() you can add and remove programmatically detail and list actions with addDetailAction(), removeDetailAction(), addListAction() and removeListAction(), see API doc for org.openxava.view.View.
Refining collection view default behavior
Using @NewAction, @SaveAction, @HideDetailAction, @RemoveAction and @RemoveSelectedAction you can refine the default behavior of collection view. For example if you want to refine the behavior of save a detail action you can define your view in this way:You must have an action DeliveryDetails.save in your controllers.xml:
And define your action class for saving:
The more common case is extending the default behavior, for that you have to extend the original class for saving a collection detail (1), that is SaveElementInCollection action, then call to super from execute() method (2), and after it, writing your own code.
Also it's possible to remove any of these actions from User Interface, for example, you can define a collection in this way:
In this case the action for removing the selected elements in the collection will be missing in the User Interface. As you see, only it's needed to declare an empty string as the name of the action.
Transient properties for UI controls
With @Transient (JPA) you define a property that is not stored in database but you want to show to the user. You can use it to provide UI controls to allow the user to manage his user interface.An example:
You can see that the syntax is exactly the same as in the case of a regular property of an entity; you can even use enum and @DefaultValueCalculator. After defining the property you can use it in the view as usual, for example with @OnChange or putting it as member of a view.
View actions
In addition of associating actions to a property, reference or collection, you also can define arbitrary actions inside your view, in any place. In order to do this we use the qualified name of action using brackets () as suffix, in this way:The visual effect will be:
You can see the link 'Change name label' that will execute the action Customer.changeNameLabel on click on it.
If the container view of the action is not editable, the action is not present. If you want that the action is always enabled, even if the view is not editable, you have to use put the word ALWAYS between the brackets, as following:
The standard way to expose actions to the user is using the controllers (actions in a bar), the controllers are reusable between views, but sometimes you will need an action specific to a view, and you want display it inside the view (not in the button bar), for these cases the view actions may be useful.
See more about actions in chapter 7.
Transient class: Only for creating views
In OpenXava it is not possible to have a view without model. Thus if you want to draw an arbitrary user interface, you need to create a class, not to declare it as entity and define your view in it.An transient class is not associated to any table of the database, typically it's used only for display User Interfaces not related to any data in database.
An example can be:
For defining a model class as transient you only need to define a regular Java class without @Entity annotation. You mustn't put the mapping annotations nor declare properties as key.
This way you can design a dialog that can be useful, for example, to print a report of families or products filtered by subfamily.
Transient classes are used with only detail modules.
The package for transient model classes must be the same of the persistent classes.
With this simple trick you can use OpenXava as a simple and flexible generator for user interfaces although the displayed data won't be stored.